# 基于感知哈希算法(perceptual Hash algorithm)的以图搜图

# 哈希值是数据的指纹，是数据独一无二的特征值。
# 任何微小的差异都将引起两个数据的哈希值产生巨大的差异。

# 感知哈希值
# 一般来说，相似的图像即使在尺度、纵横比不同集颜色(对比度、亮度等)存在微小差异的情况下，
# 它们仍然具有相似的感知哈希值。因此可用来 以图搜图

# 关键问题
# 1.提取哪些特征；图像有很多特征，要找到有用的特征
# 2.如何量化特征；特征量化为数值
# 3.如何计算距离；选取计算距离的公式(欧式距离、汉明距离、曼哈顿距离)

# 流程
# 1.取小范围前景
# 2.取灰度图像
# 3.哈希矩阵
# 4.感知哈希值

import cv2
import numpy

# 返回感知哈希值的差;差值越小越近似
# template:模板图像，灰度图像
# detect:被检测图像，灰度图像
# width:图像宽
# height:图像高
def search_image(template, detect, width, height)->float:
    if not isinstance(template, numpy.ndarray):
        return -1.0
    
    # 校验模板图像的shape
    if template.shape != (width, height, 1):
        return -1.0
    
    if not isinstance(detect, numpy.ndarray):
        return -1.0
    
    # 校验被检测图像的shape
    if detect.shape != (width, height, 1):
        return -1.0
    
    threshold_ret = 0.0
    
    # 计算模板图像的均值
    template_mean = numpy.mean(template)
    
    # 使用模板图像的均值二值化，得到哈希矩阵
    threshold_ret, template_hash_mat = cv2.threshold(template, template_mean, 255.0, cv2.THRESH_BINARY)
    
    # 计算被检测的均值
    detect_mean = numpy.mean(detect)
    # 使用被检测图像的均值二值化，得到哈希矩阵
    threshold_ret, detect_hash_mat = cv2.threshold(detect, detect_mean, 255.0, cv2.THRESH_BINARY)
    
    # # 哈希矩阵转化为一维数组(感知哈希值)
    # template_hash_mat.reshap(-1)
    
    # # 哈希矩阵转化为一维数组(感知哈希值)
    # detect_hash_mat.reshap(-1)
    
    # 对两个哈希矩阵求异或(哈希矩阵差-汉明距离)
    diff_hash_mat = cv2.bitwise_xor(template_hash_mat, detect_hash_mat)
    
    # 计算差值矩阵总和
    diff_float = cv2.sumElems(diff_hash_mat)
    
    return diff_float / 255.0
